# 导入Django相关模块
from django.shortcuts import render, redirect  # 模板渲染和页面重定向
from django.utils import timezone  # 处理时区相关的时间操作
from datetime import timedelta  # 用于时间间隔计算
from django.contrib import messages  # 消息框架（用于页面提示）
from django.db import transaction  # 数据库事务支持
from django.db.models import F  # F表达式（避免竞争条件）
from .models import LotteryData, UserProfile, BetRecord  # 自定义数据模型
from django.contrib.auth.decorators import login_required  # 登录验证装饰器
from django.views.decorators.http import require_POST  # 限制只接受POST请求的装饰器
from django.db.models import Sum  # 添加在已有导入之后
from django.urls import reverse


# 定义投注类型及其验证函数（包含赔率信息）
BET_TYPES = {
    # 基础类型（赔率2倍）
    'small': lambda x: 0 <= x <= 13,  # 小（0-13）
    'big': lambda x: 14 <= x <= 27,  # 大（14-27）
    'odd': lambda x: x % 2 == 1,  # 奇数
    'even': lambda x: x % 2 == 0 or x == 0,  # 偶数（包含0的特殊处理）

    # 组合类型（赔率4倍，使用下划线连接）
    'small_odd': lambda x: 0 <= x <= 13 and x % 2 == 1,  # 小+奇数
    'small_even': lambda x: 0 <= x <= 13 and (x % 2 == 0 or x == 0),  # 小+偶数
    'big_odd': lambda x: 14 <= x <= 27 and x % 2 == 1,  # 大+奇数
    'big_even': lambda x: 14 <= x <= 27 and x % 2 == 0  # 大+偶数
}

# 新增数字类型投注（0-27）
number_bets = {str(i): lambda x: x == i for i in range(28)}
BET_TYPES.update(number_bets)

# 数字类型对应赔率表
number_odds = {
    '0': 488, '1': 128, '2': 88, '3': 58, '4': 48, '5': 38, '6': 28,
    '7': 18, '8': 15, '9': 15, '10': 14, '11': 13, '12': 12, '13': 13,
    '14': 14, '15': 15, '16': 15, '17': 18, '18': 18, '19': 18, '20': 18,
    '21': 28, '22': 38, '23': 48, '24': 58, '25': 88, '26': 128, '27': 488
}


@login_required
def lottery_list(request):
    """彩票列表视图（核心功能）"""
    try:
        with transaction.atomic():
            user_profile = UserProfile.objects.get(user=request.user)
            current_entry = LotteryData.objects.filter(status='pending').order_by('-issue_number').first()
            latest_settled = LotteryData.objects.filter(status='closed').order_by('-issue_number').first()

            remaining_time = 0
            allow_betting = False
            current_issue_number = None

            if latest_settled and not BetRecord.objects.filter(issue=latest_settled.issue_number,
                                                               result__isnull=False).exists():
                settle_previous_bets(latest_settled)

            if current_entry:
                end_time = current_entry.start_time + timedelta(seconds=180)
                remaining = (end_time - timezone.now()).total_seconds()
                remaining_time = max(int(remaining), 0)
                allow_betting = remaining > 30
                current_issue_number = current_entry.issue_number
            elif latest_settled:
                next_issue = int(latest_settled.issue_number) + 1
                remaining_time = 180
            #当日流水
            daily_flow = BetRecord.objects.filter(
                user=request.user,
                created_at__range=(timezone.now().replace(hour=0, minute=0, second=0, microsecond=0),
                                   timezone.now().replace(hour=23, minute=59, second=59, microsecond=999999)),
                is_cancelled=False,
                is_settled=False  # 必须添加此条件
            ).aggregate(total=Sum('amount'))['total'] or 0

            # 新增下家流水计算
            current_profile = request.user.profile
            invitee_profiles = current_profile.invitees.all()
            invitee_users = [profile.user for profile in invitee_profiles]

            invitee_daily_flow = BetRecord.objects.filter(
                user__in=invitee_users,
                created_at__range=(timezone.now().replace(hour=0, minute=0, second=0, microsecond=0),
                                   timezone.now().replace(hour=23, minute=59, second=59, microsecond=999999)),
                is_cancelled=False,
                is_settled=False
            ).aggregate(total=Sum('amount'))['total'] or 0

            context = {
                'current_issue': current_issue_number or next_issue or "等待开奖",
                'remaining_time': remaining_time,
                'allow_betting': allow_betting,
                'user_score': user_profile.score,
                'entries': LotteryData.objects.all().order_by('-issue_number')[:20],
                'bet_records': BetRecord.objects.filter(user=request.user).order_by('-created_at')[:10],
                'current_issue_number': current_issue_number,
                'daily_flow': daily_flow,
                'invitee_daily_flow': invitee_daily_flow,
            }

            if request.method == 'POST' and allow_betting and current_entry:
                return handle_bet(request, current_entry.issue_number, user_profile)

    except Exception as e:
        messages.error(request, f"系统错误：{str(e)}")
        return redirect('lottery-list')  # 确保有返回
    return render(request, 'lottery_list.html', context)


@login_required
def generate_invite_link(request):
    invite_code = request.user.profile.invite_code
    # 使用反向解析生成正确路径
    invite_path = reverse('register') + f'?invite_code={invite_code}'
    invite_url = request.build_absolute_uri(invite_path)
    return render(request, 'generate_invite_link.html', {'invite_url': invite_url})


@login_required
def invitee_bets(request):
    try:
        # 获取当前用户的 UserProfile
        current_profile = request.user.profile  # 通过 related_name='profile' 反向获取

        # 获取被邀请的 UserProfile 集合（通过反向关联 invitees）
        invitee_profiles = current_profile.invitees.all()

        # 提取对应的 User 对象列表
        invitee_users = [profile.user for profile in invitee_profiles]

        # 查询 BetRecord
        bet_records = BetRecord.objects.filter(user__in=invitee_users).select_related('user').order_by('-created_at')

        return render(request, 'invitee_bets.html', {'bet_records': bet_records})

    except UserProfile.DoesNotExist:
        messages.error(request, "用户信息不存在")
        return redirect('lottery-list')

@require_POST
@login_required
def cancel_bet(request):
    """取消下注视图"""
    try:
        with transaction.atomic():
            bet_id = request.POST.get('bet_id')
            bet = BetRecord.objects.get(
                id=bet_id,
                user=request.user,
                result__isnull=True,
                is_cancelled=False
            )

            current_entry = LotteryData.objects.filter(status='pending').first()
            if not current_entry or bet.issue != current_entry.issue_number:
                raise ValueError("该期已截止取消")

            end_time = current_entry.start_time + timedelta(seconds=180)
            if (end_time - timezone.now()).total_seconds() <= 30:
                raise ValueError("已过取消时间")

            bet.is_cancelled = True
            bet.save()
            UserProfile.objects.filter(user=request.user).update(score=F('score') + bet.amount)
            messages.success(request, f"成功取消下注，返还 {bet.amount} 积分")

    except BetRecord.DoesNotExist:
        messages.error(request, "无效的下注记录")
    except Exception as e:
        messages.error(request, f"取消失败：{str(e)}")

    return redirect('lottery-list')


def settle_previous_bets(entry):
    """优化后的结算逻辑"""
    with transaction.atomic():
        unsettled_bets = BetRecord.objects.filter(
            issue=entry.issue_number,
            result__isnull=True,
            is_cancelled=False
        )

        try:
            sum_value = int(entry.sum_value)
        except (ValueError, TypeError):
            sum_value = -1

        for bet in unsettled_bets:
            if bet.bet_type not in BET_TYPES:
                bet.result = False
                bet.save()
                continue

            check_function = BET_TYPES[bet.bet_type]
            is_valid = check_function(sum_value) if sum_value >= 0 else False
            bet.result = is_valid

            # 1. 处理数字类型（独立计算）
            if bet.bet_type in number_odds:
                if sum_value == int(bet.bet_type):
                    odds = number_odds[bet.bet_type]
                else:
                    bet.result = False
                    odds = 0
            # 2. 处理13/14特殊回本规则
            elif sum_value in [13, 14]:
                if bet.bet_type == 'small_odd' and sum_value == 13:
                    bet.result = True
                    odds = 1  # 回本
                elif bet.bet_type == 'big_even' and sum_value == 14:
                    bet.result = True
                    odds = 1  # 回本
                else:
                    odds = 1.6
            # 3. 处理组合类型
            elif '_' in bet.bet_type:
                odds = 4.6 if bet.bet_type in ['small_odd', 'big_even'] else 4.2
            # 4. 基础类型
            else:
                odds = 2

            # 执行结算（仅当结果有效且赔率>0时）
            if bet.result and odds > 0:
                UserProfile.objects.filter(user=bet.user).update(
                    score=F('score') + bet.amount * odds
                )

            bet.save()


def handle_bet(request, issue_number, profile):
    """处理下注逻辑"""
    try:
        with transaction.atomic():
            current_entry = LotteryData.objects.filter(status='pending').order_by('-issue_number').first()

            if not current_entry or current_entry.issue_number != issue_number:
                raise ValueError("当前期已结束，请刷新页面获取最新信息")

            end_time = current_entry.start_time + timedelta(seconds=180)
            remaining = (end_time - timezone.now()).total_seconds()
            if remaining <= 30:
                raise ValueError("本期已封盘，请等待下期")

            amount = int(request.POST['amount'])
            bet_type = request.POST['bet_type']

            if bet_type not in BET_TYPES:
                raise ValueError("无效投注类型")
            if amount < 10 or amount > profile.score:
                raise ValueError("金额需≥10且≤可用积分")

            expected_score = profile.score - amount
            bet_record = BetRecord.objects.create(
                user=request.user,
                issue=issue_number,
                bet_type=bet_type,
                amount=amount,
                current_score=expected_score,
                result=None
            )

            profile.score = F('score') - amount
            profile.save()
            profile.refresh_from_db()
            bet_record.current_score = profile.score
            bet_record.save()

            messages.success(request, f"成功下注{amount}积分（类型：{bet_type}）")

    except Exception as e:
        messages.error(request, f"下注失败：{str(e)}")

    return redirect('lottery-list')
